﻿using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using MediaAssistant.DAL;
using MediaAssistant.DAL.Constants;
using MediaAssistant.DAL.Helper;
using MefBasic.Helper;
using Newtonsoft.Json.Linq;

namespace MediaAssistant.Management
{
    [Export]
    public class IMDBMovieScanner : BackgroundScanner
    {
        public IMDBMovieScanner()
        {
            Name = "IMDB Movie Scanner";
        }
        protected override void TryToScan()
        {
            var moviesToScan = DatabaseManager.Instance.GetProcessingMovies();
            if (moviesToScan != null && moviesToScan.Any())
            {
                foreach (var movie in moviesToScan.OrderByDescending(m=>m.FullPath))
                {
                    if (Job.Store.StopRequested)
                    {
                        return;
                    }
                    Thread.Sleep(100);
                    PauseIfRequested();
                    JObject jsonObject;
                    ProcessMovie(movie, out jsonObject);
                }
                DatabaseManager.Instance.UpdateProcessingMovies();
            }
        }

        public void ProcessMovie(Movie movie, out JObject jsonObject)
        {
            DatabaseManager.Instance.MarkAsProcessing(movie);
            jsonObject = GetMovieDetails(GetImdbApiUrl(movie.Title));
            if (!string.IsNullOrWhiteSpace(movie.Title) && UpdateMovieFromIMDB(movie, jsonObject)) 
                return;
            jsonObject = GetMovieDetails(GetImdbApiUrlFromId(movie.IMDBId));
            if (string.IsNullOrEmpty(movie.IMDBId) == false && UpdateMovieFromIMDB(movie, jsonObject))
                return;
            if(string.IsNullOrWhiteSpace(movie.FullPath))
            {
                DatabaseManager.Instance.MarkAsFailed(movie);
                jsonObject = null;
                return;
            }

            jsonObject = GetMovieDetailsFromFileName(movie.FullPath);

            UpdateMovieFromIMDB(movie, jsonObject);
        }

        public static JObject GetMovieDetailsFromFileName(string fullPath)
        {
            
            string firstCandidate;
            string secondCandidate;
            GetCandidateTitle(fullPath, out firstCandidate, out secondCandidate);
            var jsonObject = GetMovieDetails(GetImdbApiUrl(firstCandidate)) ?? GetMovieDetails(GetImdbApiUrl(secondCandidate));

            if (MediaHelper.HasError(jsonObject))
            {
                jsonObject = GetMovieDetails(GetImdbApiUrl(secondCandidate));
            }
            return jsonObject;
        }

        public static void GetCandidateTitle(string fullPath, out string firstCandidate, out string secondCandidate)
        {
            var fileInfo = new FileInfo(fullPath);
            if (File.Exists(fullPath)==false || Utility.GetSupportedMovieCount(fileInfo.Directory.FullName) == 1)
            {
                firstCandidate = CorrectTitle(fileInfo.Directory.Name);
                secondCandidate = CorrectTitle(Path.GetFileNameWithoutExtension(fullPath));
            }
            else
            {
                firstCandidate = CorrectTitle(Path.GetFileNameWithoutExtension(fullPath));
                secondCandidate = CorrectTitle(fileInfo.Directory.Name);
            }
        }
        private static string CorrectTitle(string title)
        {
            var token = title.Trim().Split("`~!^*()[]{};<>+-".ToCharArray());
            title = Regex.Replace(token.First(), "[._]", " ");// token.First().Trim().Replace(".", " ").Replace("_", " ");
            int index = title.IndexOf("720p", StringComparison.OrdinalIgnoreCase);
            if(index>0)
                title = title.Substring(0, index);
            index = title.IndexOf("480p", StringComparison.OrdinalIgnoreCase);
            if (index > 0)
                title = title.Substring(0, index);
            index = title.IndexOf("1080p", StringComparison.OrdinalIgnoreCase);
            if (index > 0)
                title = title.Substring(0, index);
            index = title.IndexOf("brrip", StringComparison.OrdinalIgnoreCase);
            if (index > 0)
                title = title.Substring(0, index);
            index = title.IndexOf("bdrip", StringComparison.OrdinalIgnoreCase);
            if (index > 0)
                title = title.Substring(0, index);
            index = title.IndexOf("Dvdrip", StringComparison.OrdinalIgnoreCase);
            if (index > 0)
                title = title.Substring(0, index);
            if(title.Length>4)
            {
                title=Regex.Split(title, @"(?<Year> \d{4})").First();
            }
            return title.Trim();
        }

        private bool UpdateMovieFromIMDB(Movie movie, JObject jsonObject)
        {
            try
            {
                if (jsonObject == null)
                    return false;

                if (MediaHelper.HasError(jsonObject))
                {
                    DatabaseManager.Instance.MarkAsFailed(movie);
                    return false;
                }

                if (movie.Status == MovieStatus.Creating)
                {
                    movie.UpdateMovie(jsonObject);
                }
                else
                {
                    SynchronizationContextHelper.Instance.SendInBackground(UpdateMovie, new object[] {movie, jsonObject});
                }

                return true;
            }
            catch (Exception)
            {
                DatabaseManager.Instance.MarkAsFailed(movie);
                return false;
            }
        }

        private static JObject GetMovieDetails(string imdbApiUrl)
        {
            try
            {
                return JObject.Parse(WebRequestHelper.GetContent(imdbApiUrl));
            }
            catch (Exception)
            {
                return null;
            }
        }

        private void UpdateMovie(object state)
        {
            var objArray = (object[]) state;
            DataSource.Value.UpdateMovie((Movie) objArray[0], (JObject) objArray[1]);
            DatabaseManager.Instance.UpdateProcessingTitle(DataSource.Value.ShowDrivesMoviesOnly);
            DatabaseManager.Instance.UpdateFailedTitle(DataSource.Value.ShowDrivesMoviesOnly);
        }

        private static string GetImdbApiUrl(string title)
        {
            return string.Format("http://www.imdbapi.com/?i=&t={0}", title);
        }
        private static string GetImdbApiUrlFromId(string imdbId)
        {
            return string.Format("http://www.imdbapi.com/?i={0}&t=", imdbId);
        }
    }
}